Introduction
Bike share systems provide an eco-friendly transportation option, but
one of the bog operational challenge is “re-balancing”, which ensuring
bikes are evenly distributed across stations to meet demand. This
analysis examines bike prediction for the NY city Bike in Jersey city,
which utilize NY city Bike data in April, 2022, along with census and
climate information.
By developing a space-time predictive model, the study identifies
patterns in bike demand based on socio-economic factors, weather, and
commuting trends, particularly near high-demand areas like the Hudson
River and Manhattan. These insights aim to improve bike re-balancing
strategies, ensuring efficient operations and better user
satisfaction.
Weather data
Since this analysis focuses on Jersey City, weather data from Newark
Airport (EWR) is used. The following time series plots display
precipitation, wind speed, and temperature for each hour in Jersey City
during April 2022. The plots reveal a few days of precipitation, with a
noticeable increase in temperature around mid-April.
grid.arrange(
ggplot(weather.Panel, aes(interval60,Precipitation)) + geom_line() +
labs(title="Percipitation", x="Hour", y="Perecipitation") + plotTheme,
ggplot(weather.Panel, aes(interval60,Wind_Speed)) + geom_line() +
labs(title="Wind Speed", x="Hour", y="Wind Speed") + plotTheme,
ggplot(weather.Panel, aes(interval60,Temperature)) + geom_line() +
labs(title="Temperature", x="Hour", y="Temperature") + plotTheme,
top="Weather Data - ERW airport - Arpil, 2022")

Describe and Explore the Data
The Time Series Plot below illustrate Bike share tripe per hours in
Jersey City. The blue line is used to visualize the Friday.
In can see the relatively low ride share in early April.
ggplot(dat_census %>%
group_by(interval60) %>%
tally())+
geom_line(aes(x = interval60, y = n))+
labs(title="Bike share trips per hr. Jersey City, April, 2022",
x="Date",
y="Number of trips")+
#geom_vline(data = monday, aes(xintercept = monday), color = "red") +
geom_vline(data = Friday, aes(xintercept = Friday), color = "blue") +
plotTheme

The following plots display bike share trips in Jersey City, broken
down by day of the week and by weekdays versus weekends. The data shows
a peak in trip counts on Fridays, with overall higher trip volumes on
weekdays compared to weekends. This trend indicates that bike sharing is
more commonly used for commuting or weekday activities than for weekend
use.
ggplot(dat_census %>% mutate(hour = hour(started_at)))+
geom_freqpoly(aes(hour, color = dotw), binwidth = 1)+
labs(title="Bike share trips in Jersey, by day of the week, April, 2022",
x="Hour",
y="Trip Counts")+
plotTheme

ggplot(dat_census %>%
mutate(hour = hour(started_at),
weekend = ifelse(dotw %in% c("Sun", "Sat"), "Weekend", "Weekday")))+
geom_freqpoly(aes(hour, color = weekend), binwidth = 1)+
labs(title="Bike share trips in Jersey - weekend vs weekday, April, 2022",
x="Hour",
y="Trip Counts")+
plotTheme

The maps below show the hourly bike share trips by station. Weekdays
generally have higher bike share trips compared to weekends. Overall,
stations near the Hudson River, especially those close to Manhattan,
exhibit relatively higher bike share counts, particularly during weekday
PM rush hours.
ggplot()+
geom_sf(data = NJTracts %>%
st_transform(crs=4326))+
geom_point(data = dat_census %>%
mutate(hour = hour(started_at),
weekend = ifelse(dotw %in% c("Sun", "Sat"), "Weekend", "Weekday"),
time_of_day = case_when(hour(interval60) < 7 | hour(interval60) > 19 ~ "Overnight",
hour(interval60) >= 7 & hour(interval60) < 10 ~ "AM Rush",
hour(interval60) >= 10 & hour(interval60) < 15 ~ "Mid-Day",
hour(interval60) >= 15 & hour(interval60) <= 19 ~ "PM Rush"))%>%
group_by(start_station_id, start_lat, start_lng, weekend, time_of_day) %>%
tally() ,
aes(x=start_lng, y = start_lat, color = n),
fill = "transparent", alpha = 0.9, size = 0.9)+
scale_colour_viridis(direction = -1,
discrete = FALSE, option = "D")+
ylim(min(dat_census$start_lat), max(dat_census$start_lat))+
xlim(min(dat_census$start_lng), max(dat_census$start_lng))+
facet_grid(weekend ~ time_of_day)+
labs(title="Bike share trips per hr by station. Jersey, April, 2022")+
mapTheme

Run Model and Predict for test data
This section split data into a training and test set and develop a 3
week training set and a 2 week test set of all the stations. In the
following analysis, four different linear regression are estimated on
ride.Train. - reg 1 focuses on just time,
including hour fixed effects, day of week and weather temperature -
reg 2 focuses on space effect with the station name fixed
effects. - reg 3 focuses on both time and space fixed
effects. - reg 4 adds the lag features.
The time lag variables will add additional nuance about the demand
during a given time period - hours before and during that day.
ride.Train <- filter(ride.panel, week >= 15)
ride.Test <- filter(ride.panel, week < 15)
reg1 <-
lm(Trip_Count ~ hour(interval60) + dotw + Temperature, data=ride.Train)
reg2 <-
lm(Trip_Count ~ start_station_name + dotw + Temperature, data=ride.Train)
reg3 <-
lm(Trip_Count ~ start_station_name + hour(interval60) + dotw + Temperature + Precipitation,
data=ride.Train)
reg4 <-
lm(Trip_Count ~ start_station_name + hour(interval60) + dotw + Temperature + Precipitation +
lagHour + lag2Hours +lag3Hours + lag12Hours + lag1day,
data=ride.Train)
#reg5 <-
#lm(Trip_Count ~ start_station_name + hour(interval60) + dotw + Temperature + Precipitation +
#lagHour + lag2Hours +lag3Hours +lag12Hours + lag1day + holiday,
#data=ride.Train)
ride.Test.weekNest <-
ride.Test %>%
nest(-week)
model_pred <- function(dat, fit){
pred <- predict(fit, newdata = dat)}
Mean Absolute Error (MAE) is calculated on ride.Test for
each model. The plots below illustrate the MAE values for the four
models. It displays the highest MAE value in the model that only focuses
on time, and the lowest MAE value in the model that add lag
features. Therefore, the time lag feature lead the model be better
prediction.
week_predictions %>%
dplyr::select(week, Regression, MAE) %>%
gather(Variable, MAE, -Regression, -week) %>%
ggplot(aes(week, MAE)) +
geom_bar(aes(fill = Regression), position = "dodge", stat="identity") +
scale_fill_manual(values = palette5) +
labs(title = "Mean Absolute Errors by model specification and week") +
plotTheme

The time series plot below shows the predicted and observed bike
counts for a 2-week test set. Overall, the models tend to under-predict
the observed values. Among all regression models, Model 4, which
incorporates all features, demonstrates the highest accuracy. Therefore,
the subsequent analysis is based on Model 4.
week_predictions %>%
mutate(interval60 = map(data, pull, interval60),
start_station_id = map(data, pull, start_station_id)) %>%
dplyr::select(interval60, start_station_id, Observed, Prediction, Regression) %>%
unnest() %>%
gather(Variable, Value, -Regression, -interval60, -start_station_id) %>%
group_by(Regression, Variable, interval60) %>%
summarize(Value = sum(Value)) %>%
ggplot(aes(interval60, Value, colour=Variable)) +
geom_line(size = 1.1) +
facet_wrap(~Regression, ncol=1) +
labs(title = "Predicted/Observed bike share time series", subtitle = "Jersey; A test set of 2 weeks", x = "Hour", y= "Station Trips") +
plotTheme

The map below displays the distribution of MAE values using Model 4
in Jersey City. Higher MAE values are observed near the Hudson River,
particularly in areas closer to Manhattan.
week_predictions %>%
mutate(interval60 = map(data, pull, interval60),
start_station_id = map(data, pull, start_station_id),
start_lat = map(data, pull, start_lat),
start_lng = map(data, pull, start_lng)) %>%
select(interval60, start_station_id, start_lng, start_lat, Observed, Prediction, Regression) %>%
unnest() %>%
filter(Regression == "DTime_Space_FE_timeLags") %>%
group_by(start_station_id, start_lng, start_lat) %>%
summarize(MAE = mean(abs(Observed-Prediction), na.rm = TRUE))%>%
ggplot(.)+
geom_sf(data = NJ_Census, color = "grey", fill = "transparent")+
geom_point(aes(x = start_lng, y = start_lat, color = MAE, size = MAE),
fill = "transparent", alpha = 0.8) +
scale_colour_viridis(
name = "Mean Absolute Error", # Combined title for color and size
direction = -1,
option = "D",
discrete = FALSE
) +
scale_size_continuous(
name = "Mean Absolute Error", # Same title as color to combine legend
range = c(1, 5) # Adjust size range as needed
) +
guides(
color = guide_legend() # Use a single legend guide
) +
ylim(min(dat_census$start_lat), max(dat_census$start_lat))+
xlim(min(dat_census$start_lng), max(dat_census$start_lng))+
labs(title="Mean Abs Error, Test Set, Model 4")+
mapTheme

Space-Time Error Evaluation
The following scatterplots show the observed versus predicted values
for different time periods of the day on weekdays and weekends. Overall,
the predicted values tend to under-predict the observed values. However,
the weekend exhibits relatively smaller errors compared to weekdays, as
indicated by the red line being closer to the black line.
week_predictions %>%
mutate(interval60 = map(data, pull, interval60),
start_station_id = map(data, pull, start_station_id),
start_lat = map(data, pull, start_lat),
start_lng = map(data, pull, start_lng),
dotw = map(data, pull, dotw)) %>%
select(interval60, start_station_id, start_lng,
start_lat, Observed, Prediction, Regression,
dotw) %>%
unnest() %>%
filter(Regression == "DTime_Space_FE_timeLags")%>%
mutate(weekend = ifelse(dotw %in% c("Sun", "Sat"), "Weekend", "Weekday"),
time_of_day = case_when(hour(interval60) < 7 | hour(interval60) > 18 ~ "Overnight",
hour(interval60) >= 7 & hour(interval60) < 10 ~ "AM Rush",
hour(interval60) >= 10 & hour(interval60) < 15 ~ "Mid-Day",
hour(interval60) >= 15 & hour(interval60) <= 18 ~ "PM Rush"))%>%
ggplot()+
geom_point(aes(x= Observed, y = Prediction))+
geom_smooth(aes(x= Observed, y= Prediction), method = "lm", se = FALSE, color = "red")+
geom_abline(slope = 1, intercept = 0)+
facet_grid(time_of_day~weekend)+
labs(title="Observed vs Predicted",
x="Observed trips",
y="Predicted trips")+
plotTheme

The maps below display the distribution of MAE values in Jersey City
during different time periods on weekdays and weekends. Overall, areas
near the Hudson River exhibit relatively higher MAE values.
Additionally, the model performs better during the overnight period, as
indicated by lower MAE values.
week_predictions %>%
mutate(interval60 = map(data, pull, interval60),
start_station_id = map(data, pull, start_station_id),
start_lat = map(data, pull, start_lat),
start_lng = map(data, pull, start_lng),
dotw = map(data, pull, dotw) ) %>%
select(interval60, start_station_id, start_lng,
start_lat, Observed, Prediction, Regression,
dotw) %>%
unnest() %>%
filter(Regression == "DTime_Space_FE_timeLags")%>%
mutate(weekend = ifelse(dotw %in% c("Sun", "Sat"), "Weekend", "Weekday"),
time_of_day = case_when(hour(interval60) < 7 | hour(interval60) > 18 ~ "Overnight",
hour(interval60) >= 7 & hour(interval60) < 10 ~ "AM Rush",
hour(interval60) >= 10 & hour(interval60) < 15 ~ "Mid-Day",
hour(interval60) >= 15 & hour(interval60) <= 18 ~ "PM Rush")) %>%
group_by(start_station_id, weekend, time_of_day, start_lng, start_lat) %>%
summarize(MAE = mean(abs(Observed-Prediction), na.rm = TRUE))%>%
ggplot(.)+
geom_sf(data = NJ_Census, color = "grey", fill = "transparent")+
geom_point(aes(x = start_lng, y = start_lat, color = MAE),
fill = "transparent", alpha = 0.5, size = 1.5) +
scale_colour_viridis(direction = -1,
discrete = FALSE, option = "D") +
ylim(min(dat_census$start_lat), max(dat_census$start_lat))+
xlim(min(dat_census$start_lng), max(dat_census$start_lng))+
facet_grid(weekend~time_of_day)+
labs(title="Mean Absolute Errors, Test Set")+
mapTheme

The following scatterplots explore the relationship between errors
and socio-economic features. The analysis reveals that areas with lower
income, a smaller proportion of residents using public transportation,
and a lower percentage of white residents tend to have lower MAE values,
indicating that these areas are more accurately predicted by the
model.
week_predictions %>%
mutate(interval60 = map(data, pull, interval60),
start_station_id = map(data, pull, start_station_id),
start_lat = map(data, pull, start_lat),
start_lng = map(data, pull, start_lng),
dotw = map(data, pull, dotw),
Percent_Taking_Public_Trans = map(data, pull, Percent_Taking_Public_Trans),
Med_Inc = map(data, pull, Med_Inc),
Percent_White = map(data, pull, Percent_White)) %>%
select(interval60, start_station_id, start_lat,
start_lng, Observed, Prediction, Regression,
dotw, Percent_Taking_Public_Trans, Med_Inc, Percent_White) %>%
unnest() %>%
filter(Regression == "DTime_Space_FE_timeLags")%>%
mutate(weekend = ifelse(dotw %in% c("Sun", "Sat"), "Weekend", "Weekday"),
time_of_day = case_when(hour(interval60) < 7 | hour(interval60) > 18 ~ "Overnight",
hour(interval60) >= 7 & hour(interval60) < 10 ~ "AM Rush",
hour(interval60) >= 10 & hour(interval60) < 15 ~ "Mid-Day",
hour(interval60) >= 15 & hour(interval60) <= 18 ~ "PM Rush")) %>%
filter(time_of_day == "AM Rush") %>%
group_by(start_station_id, Percent_Taking_Public_Trans, Med_Inc, Percent_White) %>%
summarize(MAE = mean(abs(Observed-Prediction), na.rm = TRUE))%>%
gather(-start_station_id, -MAE, key = "variable", value = "value")%>%
ggplot(.)+
#geom_sf(data = chicagoCensus, color = "grey", fill = "transparent")+
geom_point(aes(x = value, y = MAE), alpha = 0.4)+
geom_smooth(aes(x = value, y = MAE), method = "lm", se= FALSE)+
facet_wrap(~variable, scales = "free")+
labs(title="Errors as a function of socio-economic variables",
y="Mean Absolute Error (Trips)")+
plotTheme

Conclusion
Overall, bike stations near the Hudson River, particularly those
close to Manhattan, exhibit higher bike share counts, likely reflecting
a high volume of commuters traveling for work, study, or other daily
activities. Additionally, these stations tend to have relatively larger
Mean Absolute Error (MAE) values, showing a tendency for
under-prediction compared to other stations. This suggests a high demand
for bikes in areas near the Hudson River. To address bike re-balancing
plan, it is essential to ensure that stations anticipated to experience
high demand are adequately supplied with bikes. Based on the model
analysis, allocating more bikes to stations near the Hudson River is a
necessary step to meet this demand effectively.
LS0tCnRpdGxlOiAiSFc1YiAtIEJpa2UgU2hhcmUgUHJlZGljdGlvbiIKZGF0ZTogIjIwMjQtMTEtMTMiCmF1dGhvcjogSmlhdG9uZyBTdQpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiBzaW1wbGV4CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIHByb2dyZXNzOiBoaWRlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogIHBhcmFtczoKICBpbmNsdWRlX3dhcm5pbmdzOiBmYWxzZSAgIyBBZGQgdGhpcyBsaW5lIHRvIHN1cHByZXNzIHdhcm5pbmdzCi0tLQoKIyBJbnRyb2R1Y3Rpb24KCkJpa2Ugc2hhcmUgc3lzdGVtcyBwcm92aWRlIGFuIGVjby1mcmllbmRseSB0cmFuc3BvcnRhdGlvbiBvcHRpb24sIGJ1dCBvbmUgb2YgdGhlIGJvZyBvcGVyYXRpb25hbCBjaGFsbGVuZ2UgaXMgInJlLWJhbGFuY2luZyIsIHdoaWNoIGVuc3VyaW5nIGJpa2VzIGFyZSBldmVubHkgZGlzdHJpYnV0ZWQgYWNyb3NzIHN0YXRpb25zIHRvIG1lZXQgZGVtYW5kLiBUaGlzIGFuYWx5c2lzIGV4YW1pbmVzIGJpa2UgcHJlZGljdGlvbiBmb3IgdGhlIE5ZIGNpdHkgQmlrZSBpbiBKZXJzZXkgY2l0eSwgd2hpY2ggdXRpbGl6ZSBOWSBjaXR5IEJpa2UgZGF0YSBpbiBBcHJpbCwgMjAyMiwgYWxvbmcgd2l0aCBjZW5zdXMgYW5kIGNsaW1hdGUgaW5mb3JtYXRpb24uCgpCeSBkZXZlbG9waW5nIGEgc3BhY2UtdGltZSBwcmVkaWN0aXZlIG1vZGVsLCB0aGUgc3R1ZHkgaWRlbnRpZmllcyBwYXR0ZXJucyBpbiBiaWtlIGRlbWFuZCBiYXNlZCBvbiBzb2Npby1lY29ub21pYyBmYWN0b3JzLCB3ZWF0aGVyLCBhbmQgY29tbXV0aW5nIHRyZW5kcywgcGFydGljdWxhcmx5IG5lYXIgaGlnaC1kZW1hbmQgYXJlYXMgbGlrZSB0aGUgSHVkc29uIFJpdmVyIGFuZCBNYW5oYXR0YW4uIFRoZXNlIGluc2lnaHRzIGFpbSB0byBpbXByb3ZlIGJpa2UgcmUtYmFsYW5jaW5nIHN0cmF0ZWdpZXMsIGVuc3VyaW5nIGVmZmljaWVudCBvcGVyYXRpb25zIGFuZCBiZXR0ZXIgdXNlciBzYXRpc2ZhY3Rpb24uCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQoKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoc2YpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KHRpZ3JpcykKbGlicmFyeSh0aWR5Y2Vuc3VzKQpsaWJyYXJ5KHZpcmlkaXMpCmxpYnJhcnkocmllbSkKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkoa25pdHIpCmxpYnJhcnkodG1hcCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCgpwbG90VGhlbWUgPC0gdGhlbWUoCiAgcGxvdC50aXRsZSA9ZWxlbWVudF90ZXh0KHNpemU9MTIpLAogIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT04KSwKICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLAogIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICMgU2V0IHRoZSBlbnRpcmUgY2hhcnQgcmVnaW9uIHRvIGJsYW5rCiAgcGFuZWwuYmFja2dyb3VuZD1lbGVtZW50X2JsYW5rKCksCiAgcGxvdC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSwKICAjcGFuZWwuYm9yZGVyPWVsZW1lbnRfcmVjdChjb2xvdXI9IiNGMEYwRjAiKSwKICAjIEZvcm1hdCB0aGUgZ3JpZAogIHBhbmVsLmdyaWQubWFqb3I9ZWxlbWVudF9saW5lKGNvbG91cj0iI0QwRDBEMCIsc2l6ZT0uMiksCiAgYXhpcy50aWNrcz1lbGVtZW50X2JsYW5rKCkpCgptYXBUaGVtZSA8LSB0aGVtZShwbG90LnRpdGxlID1lbGVtZW50X3RleHQoc2l6ZT0xMiksCiAgICAgICAgICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT04KSwKICAgICAgICAgICAgICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwKICAgICAgICAgICAgICAgICAgYXhpcy5saW5lPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgIGF4aXMudGlja3M9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgcGFuZWwuYm9yZGVyPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvcj1lbGVtZW50X2xpbmUoY29sb3VyID0gJ3RyYW5zcGFyZW50JyksCiAgICAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWlub3I9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgICBsZWdlbmQuZGlyZWN0aW9uID0gInZlcnRpY2FsIiwgCiAgICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgICAgICAgICAgICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDEsIDEsIDEsIDEsICdjbScpLAogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMSwgImNtIiksIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDAuMiwgImNtIikKICAgICAgICAgICAgICAgICAgKQoKcGFsZXR0ZTUgPC0gYygiI2VmZjNmZiIsIiNiZGQ3ZTciLCIjNmJhZWQ2IiwiIzMxODJiZCIsIiMwODUxOWMiKQpwYWxldHRlNCA8LSBjKCIjRDJGQkQ0IiwiIzkyQkNBQiIsIiM1MjdEODIiLCIjMTIzRjVBIikKcGFsZXR0ZTIgPC0gYygiIzZiYWVkNiIsIiMwODUxOWMiKQoKCnRpZHljZW5zdXM6OmNlbnN1c19hcGlfa2V5KCJlNzlmMzcwNmI2ZDYxMjQ5OTY4YzZjZTg4Nzk0ZjZmNTU2ZTViZjNkIiwgb3ZlcndyaXRlID0gVFJVRSkKCmRhdCA8LSByZWFkX2NzdigiL1VzZXJzL2ppYXRvbmcvRGVza3RvcC9KQy0yMDIyMDQtY2l0aWJpa2UtdHJpcGRhdGEuY3N2IikgIzIwMjIwNAoKYGBgCgpgYGB7ciwgaW5jbHVkZT1GQUxTRX0KZGF0XzEgPC0gZGF0ICU+JQogIG11dGF0ZShpbnRlcnZhbDYwID0gZmxvb3JfZGF0ZSh5bWRfaG1zKHN0YXJ0ZWRfYXQpLCB1bml0ID0gImhvdXIiKSwKICAgICAgICAgaW50ZXJ2YWwxNSA9IGZsb29yX2RhdGUoeW1kX2htcyhzdGFydGVkX2F0KSwgdW5pdCA9ICIxNSBtaW5zIiksCiAgICAgICAgIHdlZWsgPSB3ZWVrKGludGVydmFsNjApLAogICAgICAgICBkb3R3ID0gd2RheShpbnRlcnZhbDYwLCBsYWJlbD1UUlVFKSkKCmRhdF8xWzE6MywgYygxLDQ6NyldCgpgYGAKCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQpkYXRfMSAlPiUgZ3JvdXBfYnkod2VlaykgJT4lIAogIHN1bW1hcmlzZSgKICAgIGNvdW50ID0gbigpICAjIENvdW50cyB0aGUgbnVtYmVyIG9mIGVudHJpZXMgcGVyIHdlZWsKICApICU+JSBrYWJsZSgpCmBgYAoKYGBge3IsIGluY2x1ZGU9RkFMU0V9Ck5KX0NlbnN1cyA8LSAKICBnZXRfYWNzKGdlb2dyYXBoeSA9ICJ0cmFjdCIsIAogICAgICAgICAgdmFyaWFibGVzID0gYygiQjAxMDAzXzAwMSIsICJCMTkwMTNfMDAxIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICJCMDIwMDFfMDAyIiwgIkIwODAxM18wMDEiLAogICAgICAgICAgICAgICAgICAgICAgICAiQjA4MDEyXzAwMSIsICJCMDgzMDFfMDAxIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICJCMDgzMDFfMDEwIiwgIkIwMTAwMl8wMDEiKSwgCiAgICAgICAgICB5ZWFyID0gMjAyMiwgCiAgICAgICAgICBzdGF0ZSA9ICJOSiIsIAogICAgICAgICAgZ2VvbWV0cnkgPSBUUlVFLCAKICAgICAgICAgIGNvdW50eSA9ICJIdWRzb24iLAogICAgICAgICAgb3V0cHV0ID0gIndpZGUiKSAlPiUKICByZW5hbWUoVG90YWxfUG9wID0gIEIwMTAwM18wMDFFLAogICAgICAgICBNZWRfSW5jID0gQjE5MDEzXzAwMUUsCiAgICAgICAgIE1lZF9BZ2UgPSBCMDEwMDJfMDAxRSwKICAgICAgICAgV2hpdGVfUG9wID0gQjAyMDAxXzAwMkUsCiAgICAgICAgIFRyYXZlbF9UaW1lID0gQjA4MDEzXzAwMUUsCiAgICAgICAgIE51bV9Db21tdXRlcnMgPSBCMDgwMTJfMDAxRSwKICAgICAgICAgTWVhbnNfb2ZfVHJhbnNwb3J0ID0gQjA4MzAxXzAwMUUsCiAgICAgICAgIFRvdGFsX1B1YmxpY19UcmFucyA9IEIwODMwMV8wMTBFKSAlPiUKICBzZWxlY3QoVG90YWxfUG9wLCBNZWRfSW5jLCBXaGl0ZV9Qb3AsIFRyYXZlbF9UaW1lLAogICAgICAgICBNZWFuc19vZl9UcmFuc3BvcnQsIFRvdGFsX1B1YmxpY19UcmFucywKICAgICAgICAgTWVkX0FnZSwKICAgICAgICAgR0VPSUQsIGdlb21ldHJ5KSAlPiUKICBtdXRhdGUoUGVyY2VudF9XaGl0ZSA9IFdoaXRlX1BvcCAvIFRvdGFsX1BvcCwKICAgICAgICAgTWVhbl9Db21tdXRlX1RpbWUgPSBUcmF2ZWxfVGltZSAvIFRvdGFsX1B1YmxpY19UcmFucywKICAgICAgICAgUGVyY2VudF9UYWtpbmdfUHVibGljX1RyYW5zID0gVG90YWxfUHVibGljX1RyYW5zIC8gTWVhbnNfb2ZfVHJhbnNwb3J0KSAlPiUgCiAgc3RfdHJhbnNmb3JtKGNycyA9IDQzMjYpCgoKTkpUcmFjdHMgPC0gCiAgTkpfQ2Vuc3VzICU+JQogIGFzLmRhdGEuZnJhbWUoKSAlPiUKICBkaXN0aW5jdChHRU9JRCwgLmtlZXBfYWxsID0gVFJVRSkgJT4lCiAgc2VsZWN0KEdFT0lELCBnZW9tZXRyeSkgJT4lIAogIHN0X3NmCgoKZGF0X2NlbnN1cyA8LSBzdF9qb2luKGRhdF8xICU+JSAKICAgICAgICAgIGZpbHRlcihpcy5uYShzdGFydF9sbmcpID09IEZBTFNFICYKICAgICAgICAgICAgICAgICAgIGlzLm5hKHN0YXJ0X2xhdCkgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgaXMubmEoZW5kX2xhdCkgPT0gRkFMU0UgJgogICAgICAgICAgICAgICAgICAgaXMubmEoZW5kX2xuZykgPT0gRkFMU0UpICU+JQogICAgICAgICAgc3RfYXNfc2YoLiwgY29vcmRzID0gYygic3RhcnRfbG5nIiwgInN0YXJ0X2xhdCIpLCBjcnMgPSA0MzI2KSwKICAgICAgICBOSlRyYWN0cyAlPiUKICAgICAgICAgIHN0X3RyYW5zZm9ybShjcnM9NDMyNiksCiAgICAgICAgam9pbj1zdF9pbnRlcnNlY3RzLAogICAgICAgICAgICAgIGxlZnQgPSBUUlVFKSAlPiUKICByZW5hbWUoT3JpZ2luLlRyYWN0ID0gR0VPSUQpICU+JQogIG11dGF0ZShzdGFydF9sbmcgPSB1bmxpc3QobWFwKGdlb21ldHJ5LCAxKSksCiAgICAgICAgIHN0YXJ0X2xhdCA9IHVubGlzdChtYXAoZ2VvbWV0cnksIDIpKSklPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgc2VsZWN0KC1nZW9tZXRyeSklPiUKICBzdF9hc19zZiguLCBjb29yZHMgPSBjKCJlbmRfbG5nIiwgImVuZF9sYXQiKSwgY3JzID0gNDMyNikgJT4lCiAgc3Rfam9pbiguLCBOSlRyYWN0cyAlPiUKICAgICAgICAgICAgc3RfdHJhbnNmb3JtKGNycz00MzI2KSwKICAgICAgICAgIGpvaW49c3RfaW50ZXJzZWN0cywKICAgICAgICAgIGxlZnQgPSBUUlVFKSAlPiUKICByZW5hbWUoRGVzdGluYXRpb24uVHJhY3QgPSBHRU9JRCkgICU+JQogIG11dGF0ZShlbmRfbG5nID0gdW5saXN0KG1hcChnZW9tZXRyeSwgMSkpLAogICAgICAgICBlbmRfbGF0ID0gdW5saXN0KG1hcChnZW9tZXRyeSwgMikpKSU+JQogIGFzLmRhdGEuZnJhbWUoKSAlPiUKICBzZWxlY3QoLWdlb21ldHJ5KQpgYGAKCiMgV2VhdGhlciBkYXRhCgpTaW5jZSB0aGlzIGFuYWx5c2lzIGZvY3VzZXMgb24gSmVyc2V5IENpdHksIHdlYXRoZXIgZGF0YSBmcm9tIE5ld2FyayBBaXJwb3J0IChFV1IpIGlzIHVzZWQuIFRoZSBmb2xsb3dpbmcgdGltZSBzZXJpZXMgcGxvdHMgZGlzcGxheSBwcmVjaXBpdGF0aW9uLCB3aW5kIHNwZWVkLCBhbmQgdGVtcGVyYXR1cmUgZm9yIGVhY2ggaG91ciBpbiBKZXJzZXkgQ2l0eSBkdXJpbmcgQXByaWwgMjAyMi4gVGhlIHBsb3RzIHJldmVhbCBhIGZldyBkYXlzIG9mIHByZWNpcGl0YXRpb24sIHdpdGggYSBub3RpY2VhYmxlIGluY3JlYXNlIGluIHRlbXBlcmF0dXJlIGFyb3VuZCBtaWQtQXByaWwuCgpgYGB7ciwgaW5jbHVkZT1GQUxTRX0Kd2VhdGhlci5QYW5lbCA8LSAKICByaWVtX21lYXN1cmVzKHN0YXRpb24gPSAiRVdSIiwgZGF0ZV9zdGFydCA9ICIyMDIyLTA0LTAxIiwgZGF0ZV9lbmQgPSAiMjAyMi0wNC0zMCIpICU+JQogIGRwbHlyOjpzZWxlY3QodmFsaWQsIHRtcGYsIHAwMWksIHNrbnQpJT4lCiAgcmVwbGFjZShpcy5uYSguKSwgMCkgJT4lCiAgICBtdXRhdGUoaW50ZXJ2YWw2MCA9IHltZF9oKHN1YnN0cih2YWxpZCwxLDEzKSkpICU+JQogICAgbXV0YXRlKHdlZWsgPSB3ZWVrKGludGVydmFsNjApLAogICAgICAgICAgIGRvdHcgPSB3ZGF5KGludGVydmFsNjAsIGxhYmVsPVRSVUUpKSAlPiUKICAgIGdyb3VwX2J5KGludGVydmFsNjApICU+JQogICAgc3VtbWFyaXplKFRlbXBlcmF0dXJlID0gbWF4KHRtcGYpLAogICAgICAgICAgICAgIFByZWNpcGl0YXRpb24gPSBzdW0ocDAxaSksCiAgICAgICAgICAgICAgV2luZF9TcGVlZCA9IG1heChza250KSkgJT4lCiAgICBtdXRhdGUoVGVtcGVyYXR1cmUgPSBpZmVsc2UoVGVtcGVyYXR1cmUgPT0gMCwgNDIsIFRlbXBlcmF0dXJlKSkKCmdsaW1wc2Uod2VhdGhlci5QYW5lbCkKCmBgYAoKYGBge3J9CmdyaWQuYXJyYW5nZSgKICBnZ3Bsb3Qod2VhdGhlci5QYW5lbCwgYWVzKGludGVydmFsNjAsUHJlY2lwaXRhdGlvbikpICsgZ2VvbV9saW5lKCkgKyAKICBsYWJzKHRpdGxlPSJQZXJjaXBpdGF0aW9uIiwgeD0iSG91ciIsIHk9IlBlcmVjaXBpdGF0aW9uIikgKyBwbG90VGhlbWUsCiAgZ2dwbG90KHdlYXRoZXIuUGFuZWwsIGFlcyhpbnRlcnZhbDYwLFdpbmRfU3BlZWQpKSArIGdlb21fbGluZSgpICsgCiAgICBsYWJzKHRpdGxlPSJXaW5kIFNwZWVkIiwgeD0iSG91ciIsIHk9IldpbmQgU3BlZWQiKSArIHBsb3RUaGVtZSwKICBnZ3Bsb3Qod2VhdGhlci5QYW5lbCwgYWVzKGludGVydmFsNjAsVGVtcGVyYXR1cmUpKSArIGdlb21fbGluZSgpICsgCiAgICBsYWJzKHRpdGxlPSJUZW1wZXJhdHVyZSIsIHg9IkhvdXIiLCB5PSJUZW1wZXJhdHVyZSIpICsgcGxvdFRoZW1lLAogIHRvcD0iV2VhdGhlciBEYXRhIC0gRVJXIGFpcnBvcnQgLSBBcnBpbCwgMjAyMiIpCmBgYAoKIyBEZXNjcmliZSBhbmQgRXhwbG9yZSB0aGUgRGF0YQoKYGBge3IsIGluY2x1ZGU9RkFMU0V9Cm1vbmRheSA8LSAKICBtdXRhdGUoZGF0X2NlbnN1cywKICAgICAgICAgbW9uZGF5ID0gaWZlbHNlKGRvdHcgPT0gIk1vbiIgJiBob3VyKGludGVydmFsNjApID09IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICBpbnRlcnZhbDYwLCAwKSkgJT4lCiAgZmlsdGVyKG1vbmRheSAhPSAwKQoKRnJpZGF5IDwtIAogIG11dGF0ZShkYXRfY2Vuc3VzLAogICAgICAgICBGcmlkYXkgPSBpZmVsc2UoZG90dyA9PSAiRnJpIiAmIGhvdXIoaW50ZXJ2YWw2MCkgPT0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgIGludGVydmFsNjAsIDApKSAlPiUKICBmaWx0ZXIoRnJpZGF5ICE9IDApCgpgYGAKClRoZSBUaW1lIFNlcmllcyBQbG90IGJlbG93IGlsbHVzdHJhdGUgQmlrZSBzaGFyZSB0cmlwZSBwZXIgaG91cnMgaW4gSmVyc2V5IENpdHkuIFRoZSBibHVlIGxpbmUgaXMgdXNlZCB0byB2aXN1YWxpemUgdGhlIGBGcmlkYXlgLiBJbiBjYW4gc2VlIHRoZSByZWxhdGl2ZWx5IGxvdyByaWRlIHNoYXJlIGluIGVhcmx5IEFwcmlsLgoKYGBge3J9CmdncGxvdChkYXRfY2Vuc3VzICU+JQogICAgICAgICBncm91cF9ieShpbnRlcnZhbDYwKSAlPiUKICAgICAgICAgdGFsbHkoKSkrCiAgZ2VvbV9saW5lKGFlcyh4ID0gaW50ZXJ2YWw2MCwgeSA9IG4pKSsKICBsYWJzKHRpdGxlPSJCaWtlIHNoYXJlIHRyaXBzIHBlciBoci4gSmVyc2V5IENpdHksIEFwcmlsLCAyMDIyIiwKICAgICAgIHg9IkRhdGUiLCAKICAgICAgIHk9Ik51bWJlciBvZiB0cmlwcyIpKwogICAgICAgICAgI2dlb21fdmxpbmUoZGF0YSA9IG1vbmRheSwgYWVzKHhpbnRlcmNlcHQgPSBtb25kYXkpLCBjb2xvciA9ICJyZWQiKSArCiAgICAgICAgICBnZW9tX3ZsaW5lKGRhdGEgPSBGcmlkYXksIGFlcyh4aW50ZXJjZXB0ID0gRnJpZGF5KSwgY29sb3IgPSAiYmx1ZSIpICsKCiAgcGxvdFRoZW1lCmBgYAoKYGBge3IsIGluY2x1ZGU9RkFMU0V9CmRhdF9jZW5zdXMgJT4lCiAgICAgICAgbXV0YXRlKHRpbWVfb2ZfZGF5ID0gY2FzZV93aGVuKGhvdXIoaW50ZXJ2YWw2MCkgPCA3IHwgaG91cihpbnRlcnZhbDYwKSA+IDE4IH4gIk92ZXJuaWdodCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gNyAmIGhvdXIoaW50ZXJ2YWw2MCkgPCAxMCB+ICJBTSBSdXNoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG91cihpbnRlcnZhbDYwKSA+PSAxMCAmIGhvdXIoaW50ZXJ2YWw2MCkgPCAxNSB+ICJNaWQtRGF5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG91cihpbnRlcnZhbDYwKSA+PSAxNSAmIGhvdXIoaW50ZXJ2YWw2MCkgPD0gMTggfiAiUE0gUnVzaCIpKSU+JQogICAgICAgICBncm91cF9ieShpbnRlcnZhbDYwLCBzdGFydF9zdGF0aW9uX25hbWUsIHRpbWVfb2ZfZGF5KSAlPiUKICAgICAgICAgdGFsbHkoKSU+JQogIGdyb3VwX2J5KHN0YXJ0X3N0YXRpb25fbmFtZSwgdGltZV9vZl9kYXkpJT4lCiAgc3VtbWFyaXplKG1lYW5fdHJpcHMgPSBtZWFuKG4pKSU+JQogIGdncGxvdCgpKwogIGdlb21faGlzdG9ncmFtKGFlcyhtZWFuX3RyaXBzKSwgYmlud2lkdGggPSAxKSsKICBsYWJzKHRpdGxlPSJNZWFuIE51bWJlciBvZiBIb3VybHkgVHJpcHMgUGVyIFN0YXRpb24uIEplcnNleSwgTWF5LCAyMDE4IiwKICAgICAgIHg9Ik51bWJlciBvZiB0cmlwcyIsIAogICAgICAgeT0iRnJlcXVlbmN5IikrCiAgZmFjZXRfd3JhcCh+dGltZV9vZl9kYXkpKwogIHBsb3RUaGVtZQpgYGAKClRoZSBmb2xsb3dpbmcgcGxvdHMgZGlzcGxheSBiaWtlIHNoYXJlIHRyaXBzIGluIEplcnNleSBDaXR5LCBicm9rZW4gZG93biBieSBkYXkgb2YgdGhlIHdlZWsgYW5kIGJ5IHdlZWtkYXlzIHZlcnN1cyB3ZWVrZW5kcy4gVGhlIGRhdGEgc2hvd3MgYSBwZWFrIGluIHRyaXAgY291bnRzIG9uIEZyaWRheXMsIHdpdGggb3ZlcmFsbCBoaWdoZXIgdHJpcCB2b2x1bWVzIG9uIHdlZWtkYXlzIGNvbXBhcmVkIHRvIHdlZWtlbmRzLiBUaGlzIHRyZW5kIGluZGljYXRlcyB0aGF0IGJpa2Ugc2hhcmluZyBpcyBtb3JlIGNvbW1vbmx5IHVzZWQgZm9yIGNvbW11dGluZyBvciB3ZWVrZGF5IGFjdGl2aXRpZXMgdGhhbiBmb3Igd2Vla2VuZCB1c2UuCgpgYGB7cn0KZ2dwbG90KGRhdF9jZW5zdXMgJT4lIG11dGF0ZShob3VyID0gaG91cihzdGFydGVkX2F0KSkpKwogICAgIGdlb21fZnJlcXBvbHkoYWVzKGhvdXIsIGNvbG9yID0gZG90dyksIGJpbndpZHRoID0gMSkrCiAgbGFicyh0aXRsZT0iQmlrZSBzaGFyZSB0cmlwcyBpbiBKZXJzZXksIGJ5IGRheSBvZiB0aGUgd2VlaywgQXByaWwsIDIwMjIiLAogICAgICAgeD0iSG91ciIsIAogICAgICAgeT0iVHJpcCBDb3VudHMiKSsKICAgICBwbG90VGhlbWUKCmBgYAoKYGBge3J9CmdncGxvdChkYXRfY2Vuc3VzICU+JSAKICAgICAgICAgbXV0YXRlKGhvdXIgPSBob3VyKHN0YXJ0ZWRfYXQpLAogICAgICAgICAgICAgICAgd2Vla2VuZCA9IGlmZWxzZShkb3R3ICVpbiUgYygiU3VuIiwgIlNhdCIpLCAiV2Vla2VuZCIsICJXZWVrZGF5IikpKSsKICAgICBnZW9tX2ZyZXFwb2x5KGFlcyhob3VyLCBjb2xvciA9IHdlZWtlbmQpLCBiaW53aWR0aCA9IDEpKwogIGxhYnModGl0bGU9IkJpa2Ugc2hhcmUgdHJpcHMgaW4gSmVyc2V5IC0gd2Vla2VuZCB2cyB3ZWVrZGF5LCBBcHJpbCwgMjAyMiIsCiAgICAgICB4PSJIb3VyIiwgCiAgICAgICB5PSJUcmlwIENvdW50cyIpKwogICAgIHBsb3RUaGVtZQoKYGBgCgpUaGUgbWFwcyBiZWxvdyBzaG93IHRoZSBob3VybHkgYmlrZSBzaGFyZSB0cmlwcyBieSBzdGF0aW9uLiBXZWVrZGF5cyBnZW5lcmFsbHkgaGF2ZSBoaWdoZXIgYmlrZSBzaGFyZSB0cmlwcyBjb21wYXJlZCB0byB3ZWVrZW5kcy4gT3ZlcmFsbCwgc3RhdGlvbnMgbmVhciB0aGUgSHVkc29uIFJpdmVyLCBlc3BlY2lhbGx5IHRob3NlIGNsb3NlIHRvIE1hbmhhdHRhbiwgZXhoaWJpdCByZWxhdGl2ZWx5IGhpZ2hlciBiaWtlIHNoYXJlIGNvdW50cywgcGFydGljdWxhcmx5IGR1cmluZyB3ZWVrZGF5IFBNIHJ1c2ggaG91cnMuCgpgYGB7cn0KZ2dwbG90KCkrCiAgZ2VvbV9zZihkYXRhID0gTkpUcmFjdHMgJT4lCiAgICAgICAgICBzdF90cmFuc2Zvcm0oY3JzPTQzMjYpKSsKICBnZW9tX3BvaW50KGRhdGEgPSBkYXRfY2Vuc3VzICU+JSAKICAgICAgICAgICAgbXV0YXRlKGhvdXIgPSBob3VyKHN0YXJ0ZWRfYXQpLAogICAgICAgICAgICAgICAgd2Vla2VuZCA9IGlmZWxzZShkb3R3ICVpbiUgYygiU3VuIiwgIlNhdCIpLCAiV2Vla2VuZCIsICJXZWVrZGF5IiksCiAgICAgICAgICAgICAgICB0aW1lX29mX2RheSA9IGNhc2Vfd2hlbihob3VyKGludGVydmFsNjApIDwgNyB8IGhvdXIoaW50ZXJ2YWw2MCkgPiAxOSB+ICJPdmVybmlnaHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob3VyKGludGVydmFsNjApID49IDcgJiBob3VyKGludGVydmFsNjApIDwgMTAgfiAiQU0gUnVzaCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gMTAgJiBob3VyKGludGVydmFsNjApIDwgMTUgfiAiTWlkLURheSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gMTUgJiBob3VyKGludGVydmFsNjApIDw9IDE5IH4gIlBNIFJ1c2giKSklPiUKICAgICAgICAgICAgICBncm91cF9ieShzdGFydF9zdGF0aW9uX2lkLCBzdGFydF9sYXQsIHN0YXJ0X2xuZywgd2Vla2VuZCwgdGltZV9vZl9kYXkpICU+JQogICAgICAgICAgICAgIHRhbGx5KCkgLAogICAgICAgICAgICBhZXMoeD1zdGFydF9sbmcsIHkgPSBzdGFydF9sYXQsIGNvbG9yID0gbiksIAogICAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IiwgYWxwaGEgPSAwLjksIHNpemUgPSAwLjkpKwogIHNjYWxlX2NvbG91cl92aXJpZGlzKGRpcmVjdGlvbiA9IC0xLAogIGRpc2NyZXRlID0gRkFMU0UsIG9wdGlvbiA9ICJEIikrCiAgeWxpbShtaW4oZGF0X2NlbnN1cyRzdGFydF9sYXQpLCBtYXgoZGF0X2NlbnN1cyRzdGFydF9sYXQpKSsKICB4bGltKG1pbihkYXRfY2Vuc3VzJHN0YXJ0X2xuZyksIG1heChkYXRfY2Vuc3VzJHN0YXJ0X2xuZykpKwogIGZhY2V0X2dyaWQod2Vla2VuZCB+IHRpbWVfb2ZfZGF5KSsKICBsYWJzKHRpdGxlPSJCaWtlIHNoYXJlIHRyaXBzIHBlciBociBieSBzdGF0aW9uLiBKZXJzZXksIEFwcmlsLCAyMDIyIikrCiAgbWFwVGhlbWUKCmBgYAoKYGBge3IsIGluY2x1ZGU9RkFMU0V9Cmxlbmd0aCh1bmlxdWUoZGF0X2NlbnN1cyRpbnRlcnZhbDYwKSkgKiBsZW5ndGgodW5pcXVlKGRhdF9jZW5zdXMkc3RhcnRfc3RhdGlvbl9pZCkpCgpgYGAKCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQpzdHVkeS5wYW5lbCA8LSAKICBleHBhbmQuZ3JpZChpbnRlcnZhbDYwPXVuaXF1ZShkYXRfY2Vuc3VzJGludGVydmFsNjApLCAKICAgICAgICAgICAgICBzdGFydF9zdGF0aW9uX2lkID0gdW5pcXVlKGRhdF9jZW5zdXMkc3RhcnRfc3RhdGlvbl9pZCkpICU+JQogIGxlZnRfam9pbiguLCBkYXRfY2Vuc3VzICU+JQogICAgICAgICAgICAgIHNlbGVjdChzdGFydF9zdGF0aW9uX2lkLCBzdGFydF9zdGF0aW9uX25hbWUsIE9yaWdpbi5UcmFjdCwgc3RhcnRfbG5nLCBzdGFydF9sYXQgKSU+JQogICAgICAgICAgICAgIGRpc3RpbmN0KCkgJT4lCiAgICAgICAgICAgICAgZ3JvdXBfYnkoc3RhcnRfc3RhdGlvbl9pZCkgJT4lCiAgICAgICAgICAgICAgc2xpY2UoMSkpCgpucm93KHN0dWR5LnBhbmVsKQpgYGAKCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQpyaWRlLnBhbmVsXzEgPC0gCiAgZGF0X2NlbnN1cyAlPiUKICBtdXRhdGUoVHJpcF9Db3VudGVyID0gMSkgJT4lCiAgcmlnaHRfam9pbihzdHVkeS5wYW5lbCkgJT4lIAogIGdyb3VwX2J5KGludGVydmFsNjAsIHN0YXJ0X3N0YXRpb25faWQsIHN0YXJ0X3N0YXRpb25fbmFtZSwgT3JpZ2luLlRyYWN0LCBzdGFydF9sbmcsIHN0YXJ0X2xhdCkgJT4lCiAgc3VtbWFyaXplKFRyaXBfQ291bnQgPSBzdW0oVHJpcF9Db3VudGVyLCBuYS5ybT1UKSkgJT4lCiAgbGVmdF9qb2luKHdlYXRoZXIuUGFuZWwpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBmaWx0ZXIoaXMubmEoc3RhcnRfc3RhdGlvbl9pZCkgPT0gRkFMU0UpICU+JQogIG11dGF0ZSh3ZWVrID0gd2VlayhpbnRlcnZhbDYwKSwKICAgICAgICAgZG90dyA9IHdkYXkoaW50ZXJ2YWw2MCwgbGFiZWwgPSBUUlVFKSkgJT4lCiAgZmlsdGVyKGlzLm5hKE9yaWdpbi5UcmFjdCkgPT0gRkFMU0UpCmBgYAoKYGBge3IsIGluY2x1ZGU9RkFMU0V9CnJpZGUucGFuZWwgPC0gCiAgbGVmdF9qb2luKHJpZGUucGFuZWxfMSwgTkpfQ2Vuc3VzICU+JQogICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUKICAgICAgICAgICAgICBzZWxlY3QoLWdlb21ldHJ5KSwgYnkgPSBjKCJPcmlnaW4uVHJhY3QiID0gIkdFT0lEIikpCmBgYAoKYGBge3IsIGluY2x1ZGU9RkFMU0V9CnJpZGUucGFuZWwgPC0gCiAgcmlkZS5wYW5lbCAlPiUgCiAgYXJyYW5nZShzdGFydF9zdGF0aW9uX2lkLCBpbnRlcnZhbDYwKSAlPiUgCiAgbXV0YXRlKGxhZ0hvdXIgPSBkcGx5cjo6bGFnKFRyaXBfQ291bnQsMSksCiAgICAgICAgIGxhZzJIb3VycyA9IGRwbHlyOjpsYWcoVHJpcF9Db3VudCwyKSwKICAgICAgICAgbGFnM0hvdXJzID0gZHBseXI6OmxhZyhUcmlwX0NvdW50LDMpLAogICAgICAgICBsYWc0SG91cnMgPSBkcGx5cjo6bGFnKFRyaXBfQ291bnQsNCksCiAgICAgICAgIGxhZzEySG91cnMgPSBkcGx5cjo6bGFnKFRyaXBfQ291bnQsMTIpLAogICAgICAgICBsYWcxZGF5ID0gZHBseXI6OmxhZyhUcmlwX0NvdW50LDI0KSwKICAgICAgICAgaG9saWRheSA9IGlmZWxzZSh5ZGF5KGludGVydmFsNjApID09IDE0OCwxLDApCiAgICAgICAgICkgJT4lCiAgIG11dGF0ZShkYXkgPSB5ZGF5KGludGVydmFsNjApKSAgCgphcy5kYXRhLmZyYW1lKHJpZGUucGFuZWwpICU+JQogICAgZ3JvdXBfYnkoaW50ZXJ2YWw2MCkgJT4lIAogICAgc3VtbWFyaXNlX2F0KHZhcnMoc3RhcnRzX3dpdGgoImxhZyIpLCAiVHJpcF9Db3VudCIpLCBtZWFuLCBuYS5ybSA9IFRSVUUpICU+JQogICAgZ2F0aGVyKFZhcmlhYmxlLCBWYWx1ZSwgLWludGVydmFsNjAsIC1UcmlwX0NvdW50KSAlPiUKICAgIG11dGF0ZShWYXJpYWJsZSA9IGZhY3RvcihWYXJpYWJsZSwgbGV2ZWxzPWMoImxhZ0hvdXIiLCJsYWcySG91cnMiLCJsYWczSG91cnMiLCJsYWc0SG91cnMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibGFnMTJIb3VycyIsImxhZzFkYXkiKSkpJT4lCiAgICBncm91cF9ieShWYXJpYWJsZSkgJT4lICAKICAgIHN1bW1hcml6ZShjb3JyZWxhdGlvbiA9IHJvdW5kKGNvcihWYWx1ZSwgVHJpcF9Db3VudCksMikpCgpgYGAKCiMgUnVuIE1vZGVsIGFuZCBQcmVkaWN0IGZvciB0ZXN0IGRhdGEKClRoaXMgc2VjdGlvbiBzcGxpdCBkYXRhIGludG8gYSB0cmFpbmluZyBhbmQgdGVzdCBzZXQgYW5kIGRldmVsb3AgYSAzIHdlZWsgdHJhaW5pbmcgc2V0IGFuZCBhIDIgd2VlayB0ZXN0IHNldCBvZiBhbGwgdGhlIHN0YXRpb25zLiBJbiB0aGUgZm9sbG93aW5nIGFuYWx5c2lzLCBmb3VyIGRpZmZlcmVudCBsaW5lYXIgcmVncmVzc2lvbiBhcmUgZXN0aW1hdGVkIG9uIGByaWRlLlRyYWluYC4gLSBgcmVnIDFgIGZvY3VzZXMgb24ganVzdCB0aW1lLCBpbmNsdWRpbmcgaG91ciBmaXhlZCBlZmZlY3RzLCBkYXkgb2Ygd2VlayBhbmQgd2VhdGhlciB0ZW1wZXJhdHVyZSAtIGByZWcgMmAgZm9jdXNlcyBvbiBzcGFjZSBlZmZlY3Qgd2l0aCB0aGUgc3RhdGlvbiBuYW1lIGZpeGVkIGVmZmVjdHMuIC0gYHJlZyAzYCBmb2N1c2VzIG9uIGJvdGggdGltZSBhbmQgc3BhY2UgZml4ZWQgZWZmZWN0cy4gLSBgcmVnIDRgIGFkZHMgdGhlIGBsYWdgIGZlYXR1cmVzLgoKVGhlIHRpbWUgbGFnIHZhcmlhYmxlcyB3aWxsIGFkZCBhZGRpdGlvbmFsIG51YW5jZSBhYm91dCB0aGUgZGVtYW5kIGR1cmluZyBhIGdpdmVuIHRpbWUgcGVyaW9kIC0gaG91cnMgYmVmb3JlIGFuZCBkdXJpbmcgdGhhdCBkYXkuCgpgYGB7cn0KcmlkZS5UcmFpbiA8LSBmaWx0ZXIocmlkZS5wYW5lbCwgd2VlayA+PSAxNSkKcmlkZS5UZXN0IDwtIGZpbHRlcihyaWRlLnBhbmVsLCB3ZWVrIDwgMTUpCgpyZWcxIDwtIAogIGxtKFRyaXBfQ291bnQgfiAgaG91cihpbnRlcnZhbDYwKSArIGRvdHcgKyBUZW1wZXJhdHVyZSwgIGRhdGE9cmlkZS5UcmFpbikKCnJlZzIgPC0gCiAgbG0oVHJpcF9Db3VudCB+ICBzdGFydF9zdGF0aW9uX25hbWUgKyBkb3R3ICsgVGVtcGVyYXR1cmUsICBkYXRhPXJpZGUuVHJhaW4pCgpyZWczIDwtIAogIGxtKFRyaXBfQ291bnQgfiAgc3RhcnRfc3RhdGlvbl9uYW1lICsgaG91cihpbnRlcnZhbDYwKSArIGRvdHcgKyBUZW1wZXJhdHVyZSArIFByZWNpcGl0YXRpb24sIAogICAgIGRhdGE9cmlkZS5UcmFpbikKCnJlZzQgPC0gCiAgbG0oVHJpcF9Db3VudCB+ICBzdGFydF9zdGF0aW9uX25hbWUgKyAgaG91cihpbnRlcnZhbDYwKSArIGRvdHcgKyBUZW1wZXJhdHVyZSArIFByZWNpcGl0YXRpb24gKwogICAgICAgICAgICAgICAgICAgbGFnSG91ciArIGxhZzJIb3VycyArbGFnM0hvdXJzICsgbGFnMTJIb3VycyArIGxhZzFkYXksIAogICAgIGRhdGE9cmlkZS5UcmFpbikKCiNyZWc1IDwtIAogICNsbShUcmlwX0NvdW50IH4gIHN0YXJ0X3N0YXRpb25fbmFtZSArIGhvdXIoaW50ZXJ2YWw2MCkgKyBkb3R3ICsgVGVtcGVyYXR1cmUgKyBQcmVjaXBpdGF0aW9uICsKICAgICAgICAgICAgICAgICAgICNsYWdIb3VyICsgbGFnMkhvdXJzICtsYWczSG91cnMgK2xhZzEySG91cnMgKyBsYWcxZGF5ICsgaG9saWRheSwgCiAgICAgI2RhdGE9cmlkZS5UcmFpbikKYGBgCgpgYGB7ciwgd2FybmluZz1GQUxTRX0KcmlkZS5UZXN0LndlZWtOZXN0IDwtIAogIHJpZGUuVGVzdCAlPiUKICBuZXN0KC13ZWVrKSAKCm1vZGVsX3ByZWQgPC0gZnVuY3Rpb24oZGF0LCBmaXQpewogICBwcmVkIDwtIHByZWRpY3QoZml0LCBuZXdkYXRhID0gZGF0KX0KCmBgYAoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CndlZWtfcHJlZGljdGlvbnMgPC0gCiAgcmlkZS5UZXN0LndlZWtOZXN0ICU+JSAKICAgICAgICBtdXRhdGUoQVRpbWVfRkUgPSBtYXAoLnggPSBkYXRhLCBmaXQgPSByZWcxLCAuZiA9IG1vZGVsX3ByZWQpLAogICAgICAgICAgIEJTcGFjZV9GRSA9IG1hcCgueCA9IGRhdGEsIGZpdCA9IHJlZzIsIC5mID0gbW9kZWxfcHJlZCksCiAgICAgICAgICAgQ1RpbWVfU3BhY2VfRkUgPSBtYXAoLnggPSBkYXRhLCBmaXQgPSByZWczLCAuZiA9IG1vZGVsX3ByZWQpLAogICAgICAgICAgIERUaW1lX1NwYWNlX0ZFX3RpbWVMYWdzID0gbWFwKC54ID0gZGF0YSwgZml0ID0gcmVnNCwgLmYgPSBtb2RlbF9wcmVkKSwKICAgICAgICAgICAjRVRpbWVfU3BhY2VfRkVfdGltZUxhZ3NfaG9saWRheUxhZ3MgPSBtYXAoLnggPSBkYXRhLCBmaXQgPSByZWc1LCAuZiA9IG1vZGVsX3ByZWQpCiAgICAgICAgICAgKSAlPiUgCiAgICBnYXRoZXIoUmVncmVzc2lvbiwgUHJlZGljdGlvbiwgLWRhdGEsIC13ZWVrKSAlPiUKICAgIG11dGF0ZShPYnNlcnZlZCA9IG1hcChkYXRhLCBwdWxsLCBUcmlwX0NvdW50KSwKICAgICAgICAgICBBYnNvbHV0ZV9FcnJvciA9IG1hcDIoT2JzZXJ2ZWQsIFByZWRpY3Rpb24sICB+IGFicygueCAtIC55KSksCiAgICAgICAgICAgTUFFID0gbWFwX2RibChBYnNvbHV0ZV9FcnJvciwgbWVhbiwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICBzZF9BRSA9IG1hcF9kYmwoQWJzb2x1dGVfRXJyb3IsIHNkLCBuYS5ybSA9IFRSVUUpKQoKd2Vla19wcmVkaWN0aW9ucwpgYGAKCk1lYW4gQWJzb2x1dGUgRXJyb3IgKE1BRSkgaXMgY2FsY3VsYXRlZCBvbiBgcmlkZS5UZXN0YCBmb3IgZWFjaCBtb2RlbC4gVGhlIHBsb3RzIGJlbG93IGlsbHVzdHJhdGUgdGhlIE1BRSB2YWx1ZXMgZm9yIHRoZSBmb3VyIG1vZGVscy4gSXQgZGlzcGxheXMgdGhlIGhpZ2hlc3QgTUFFIHZhbHVlIGluIHRoZSBtb2RlbCB0aGF0IG9ubHkgZm9jdXNlcyBvbiB0aW1lLCBhbmQgdGhlIGxvd2VzdCBNQUUgdmFsdWUgaW4gdGhlIG1vZGVsIHRoYXQgYWRkIGBsYWdgIGZlYXR1cmVzLiBUaGVyZWZvcmUsIHRoZSB0aW1lIGxhZyBmZWF0dXJlIGxlYWQgdGhlIG1vZGVsIGJlIGJldHRlciBwcmVkaWN0aW9uLgoKYGBge3J9CndlZWtfcHJlZGljdGlvbnMgJT4lCiAgZHBseXI6OnNlbGVjdCh3ZWVrLCBSZWdyZXNzaW9uLCBNQUUpICU+JQogIGdhdGhlcihWYXJpYWJsZSwgTUFFLCAtUmVncmVzc2lvbiwgLXdlZWspICU+JQogIGdncGxvdChhZXMod2VlaywgTUFFKSkgKyAKICAgIGdlb21fYmFyKGFlcyhmaWxsID0gUmVncmVzc2lvbiksIHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdD0iaWRlbnRpdHkiKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlNSkgKwogICAgbGFicyh0aXRsZSA9ICJNZWFuIEFic29sdXRlIEVycm9ycyBieSBtb2RlbCBzcGVjaWZpY2F0aW9uIGFuZCB3ZWVrIikgKwogIHBsb3RUaGVtZQpgYGAKClRoZSB0aW1lIHNlcmllcyBwbG90IGJlbG93IHNob3dzIHRoZSBwcmVkaWN0ZWQgYW5kIG9ic2VydmVkIGJpa2UgY291bnRzIGZvciBhIDItd2VlayB0ZXN0IHNldC4gT3ZlcmFsbCwgdGhlIG1vZGVscyB0ZW5kIHRvIHVuZGVyLXByZWRpY3QgdGhlIG9ic2VydmVkIHZhbHVlcy4gQW1vbmcgYWxsIHJlZ3Jlc3Npb24gbW9kZWxzLCBNb2RlbCA0LCB3aGljaCBpbmNvcnBvcmF0ZXMgYWxsIGZlYXR1cmVzLCBkZW1vbnN0cmF0ZXMgdGhlIGhpZ2hlc3QgYWNjdXJhY3kuIFRoZXJlZm9yZSwgdGhlIHN1YnNlcXVlbnQgYW5hbHlzaXMgaXMgYmFzZWQgb24gTW9kZWwgNC4KCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQp3ZWVrX3ByZWRpY3Rpb25zICU+JSAKICAgIG11dGF0ZShpbnRlcnZhbDYwID0gbWFwKGRhdGEsIHB1bGwsIGludGVydmFsNjApLAogICAgICAgICAgIHN0YXJ0X3N0YXRpb25faWQgPSBtYXAoZGF0YSwgcHVsbCwgc3RhcnRfc3RhdGlvbl9pZCkpICU+JQogICAgZHBseXI6OnNlbGVjdChpbnRlcnZhbDYwLCBzdGFydF9zdGF0aW9uX2lkLCBPYnNlcnZlZCwgUHJlZGljdGlvbiwgUmVncmVzc2lvbikgJT4lCiAgICB1bm5lc3QoKSAlPiUKICAgIGdhdGhlcihWYXJpYWJsZSwgVmFsdWUsIC1SZWdyZXNzaW9uLCAtaW50ZXJ2YWw2MCwgLXN0YXJ0X3N0YXRpb25faWQpICU+JQogICAgZ3JvdXBfYnkoUmVncmVzc2lvbiwgVmFyaWFibGUsIGludGVydmFsNjApICU+JQogICAgc3VtbWFyaXplKFZhbHVlID0gc3VtKFZhbHVlKSkgJT4lCiAgICBnZ3Bsb3QoYWVzKGludGVydmFsNjAsIFZhbHVlLCBjb2xvdXI9VmFyaWFibGUpKSArIAogICAgICBnZW9tX2xpbmUoc2l6ZSA9IDEuMSkgKyAKICAgICAgZmFjZXRfd3JhcCh+UmVncmVzc2lvbiwgbmNvbD0xKSArCiAgICAgIGxhYnModGl0bGUgPSAiUHJlZGljdGVkL09ic2VydmVkIGJpa2Ugc2hhcmUgdGltZSBzZXJpZXMiLCBzdWJ0aXRsZSA9ICJKZXJzZXk7IEEgdGVzdCBzZXQgb2YgMiB3ZWVrcyIsICB4ID0gIkhvdXIiLCB5PSAiU3RhdGlvbiBUcmlwcyIpICsKICAgICAgcGxvdFRoZW1lCmBgYAoKVGhlIG1hcCBiZWxvdyBkaXNwbGF5cyB0aGUgZGlzdHJpYnV0aW9uIG9mIE1BRSB2YWx1ZXMgdXNpbmcgTW9kZWwgNCBpbiBKZXJzZXkgQ2l0eS4gSGlnaGVyIE1BRSB2YWx1ZXMgYXJlIG9ic2VydmVkIG5lYXIgdGhlIEh1ZHNvbiBSaXZlciwgcGFydGljdWxhcmx5IGluIGFyZWFzIGNsb3NlciB0byBNYW5oYXR0YW4uCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0Kd2Vla19wcmVkaWN0aW9ucyAlPiUgCiAgICBtdXRhdGUoaW50ZXJ2YWw2MCA9IG1hcChkYXRhLCBwdWxsLCBpbnRlcnZhbDYwKSwKICAgICAgICAgICBzdGFydF9zdGF0aW9uX2lkID0gbWFwKGRhdGEsIHB1bGwsIHN0YXJ0X3N0YXRpb25faWQpLCAKICAgICAgICAgICBzdGFydF9sYXQgPSBtYXAoZGF0YSwgcHVsbCwgc3RhcnRfbGF0KSwgCiAgICAgICAgICAgc3RhcnRfbG5nID0gbWFwKGRhdGEsIHB1bGwsIHN0YXJ0X2xuZykpICU+JQogICAgc2VsZWN0KGludGVydmFsNjAsIHN0YXJ0X3N0YXRpb25faWQsIHN0YXJ0X2xuZywgc3RhcnRfbGF0LCBPYnNlcnZlZCwgUHJlZGljdGlvbiwgUmVncmVzc2lvbikgJT4lCiAgICB1bm5lc3QoKSAlPiUKICBmaWx0ZXIoUmVncmVzc2lvbiA9PSAiRFRpbWVfU3BhY2VfRkVfdGltZUxhZ3MiKSAlPiUKICBncm91cF9ieShzdGFydF9zdGF0aW9uX2lkLCBzdGFydF9sbmcsIHN0YXJ0X2xhdCkgJT4lCiAgc3VtbWFyaXplKE1BRSA9IG1lYW4oYWJzKE9ic2VydmVkLVByZWRpY3Rpb24pLCBuYS5ybSA9IFRSVUUpKSU+JQpnZ3Bsb3QoLikrCiAgZ2VvbV9zZihkYXRhID0gTkpfQ2Vuc3VzLCBjb2xvciA9ICJncmV5IiwgZmlsbCA9ICJ0cmFuc3BhcmVudCIpKwogIGdlb21fcG9pbnQoYWVzKHggPSBzdGFydF9sbmcsIHkgPSBzdGFydF9sYXQsIGNvbG9yID0gTUFFLCBzaXplID0gTUFFKSwgCiAgICAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IiwgYWxwaGEgPSAwLjgpICsKICBzY2FsZV9jb2xvdXJfdmlyaWRpcygKICAgIG5hbWUgPSAiTWVhbiBBYnNvbHV0ZSBFcnJvciIsICMgQ29tYmluZWQgdGl0bGUgZm9yIGNvbG9yIGFuZCBzaXplCiAgICBkaXJlY3Rpb24gPSAtMSwKICAgIG9wdGlvbiA9ICJEIiwKICAgIGRpc2NyZXRlID0gRkFMU0UKICApICsKICBzY2FsZV9zaXplX2NvbnRpbnVvdXMoCiAgICBuYW1lID0gIk1lYW4gQWJzb2x1dGUgRXJyb3IiLCAjIFNhbWUgdGl0bGUgYXMgY29sb3IgdG8gY29tYmluZSBsZWdlbmQKICAgIHJhbmdlID0gYygxLCA1KSAjIEFkanVzdCBzaXplIHJhbmdlIGFzIG5lZWRlZAogICkgKwogIGd1aWRlcygKICAgIGNvbG9yID0gZ3VpZGVfbGVnZW5kKCkgIyBVc2UgYSBzaW5nbGUgbGVnZW5kIGd1aWRlCiAgKSArCiAgeWxpbShtaW4oZGF0X2NlbnN1cyRzdGFydF9sYXQpLCBtYXgoZGF0X2NlbnN1cyRzdGFydF9sYXQpKSsKICB4bGltKG1pbihkYXRfY2Vuc3VzJHN0YXJ0X2xuZyksIG1heChkYXRfY2Vuc3VzJHN0YXJ0X2xuZykpKwogIGxhYnModGl0bGU9Ik1lYW4gQWJzIEVycm9yLCBUZXN0IFNldCwgTW9kZWwgNCIpKwogIG1hcFRoZW1lCmBgYAoKIyBTcGFjZS1UaW1lIEVycm9yIEV2YWx1YXRpb24KClRoZSBmb2xsb3dpbmcgc2NhdHRlcnBsb3RzIHNob3cgdGhlIG9ic2VydmVkIHZlcnN1cyBwcmVkaWN0ZWQgdmFsdWVzIGZvciBkaWZmZXJlbnQgdGltZSBwZXJpb2RzIG9mIHRoZSBkYXkgb24gd2Vla2RheXMgYW5kIHdlZWtlbmRzLiBPdmVyYWxsLCB0aGUgcHJlZGljdGVkIHZhbHVlcyB0ZW5kIHRvIHVuZGVyLXByZWRpY3QgdGhlIG9ic2VydmVkIHZhbHVlcy4gSG93ZXZlciwgdGhlIHdlZWtlbmQgZXhoaWJpdHMgcmVsYXRpdmVseSBzbWFsbGVyIGVycm9ycyBjb21wYXJlZCB0byB3ZWVrZGF5cywgYXMgaW5kaWNhdGVkIGJ5IHRoZSByZWQgbGluZSBiZWluZyBjbG9zZXIgdG8gdGhlIGJsYWNrIGxpbmUuCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KCndlZWtfcHJlZGljdGlvbnMgJT4lIAogICAgbXV0YXRlKGludGVydmFsNjAgPSBtYXAoZGF0YSwgcHVsbCwgaW50ZXJ2YWw2MCksCiAgICAgICAgICAgc3RhcnRfc3RhdGlvbl9pZCA9IG1hcChkYXRhLCBwdWxsLCBzdGFydF9zdGF0aW9uX2lkKSwgCiAgICAgICAgICAgc3RhcnRfbGF0ID0gbWFwKGRhdGEsIHB1bGwsIHN0YXJ0X2xhdCksIAogICAgICAgICAgIHN0YXJ0X2xuZyA9IG1hcChkYXRhLCBwdWxsLCBzdGFydF9sbmcpLAogICAgICAgICAgIGRvdHcgPSBtYXAoZGF0YSwgcHVsbCwgZG90dykpICU+JQogICAgc2VsZWN0KGludGVydmFsNjAsIHN0YXJ0X3N0YXRpb25faWQsIHN0YXJ0X2xuZywgCiAgICAgICAgICAgc3RhcnRfbGF0LCBPYnNlcnZlZCwgUHJlZGljdGlvbiwgUmVncmVzc2lvbiwKICAgICAgICAgICBkb3R3KSAlPiUKICAgIHVubmVzdCgpICU+JQogIGZpbHRlcihSZWdyZXNzaW9uID09ICJEVGltZV9TcGFjZV9GRV90aW1lTGFncyIpJT4lCiAgbXV0YXRlKHdlZWtlbmQgPSBpZmVsc2UoZG90dyAlaW4lIGMoIlN1biIsICJTYXQiKSwgIldlZWtlbmQiLCAiV2Vla2RheSIpLAogICAgICAgICB0aW1lX29mX2RheSA9IGNhc2Vfd2hlbihob3VyKGludGVydmFsNjApIDwgNyB8IGhvdXIoaW50ZXJ2YWw2MCkgPiAxOCB+ICJPdmVybmlnaHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob3VyKGludGVydmFsNjApID49IDcgJiBob3VyKGludGVydmFsNjApIDwgMTAgfiAiQU0gUnVzaCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gMTAgJiBob3VyKGludGVydmFsNjApIDwgMTUgfiAiTWlkLURheSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gMTUgJiBob3VyKGludGVydmFsNjApIDw9IDE4IH4gIlBNIFJ1c2giKSklPiUKICBnZ3Bsb3QoKSsKICBnZW9tX3BvaW50KGFlcyh4PSBPYnNlcnZlZCwgeSA9IFByZWRpY3Rpb24pKSsKICAgIGdlb21fc21vb3RoKGFlcyh4PSBPYnNlcnZlZCwgeT0gUHJlZGljdGlvbiksIG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gInJlZCIpKwogICAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwKSsKICBmYWNldF9ncmlkKHRpbWVfb2ZfZGF5fndlZWtlbmQpKwogIGxhYnModGl0bGU9Ik9ic2VydmVkIHZzIFByZWRpY3RlZCIsCiAgICAgICB4PSJPYnNlcnZlZCB0cmlwcyIsIAogICAgICAgeT0iUHJlZGljdGVkIHRyaXBzIikrCiAgcGxvdFRoZW1lCmBgYAoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CndlZWtfcHJlZGljdGlvbnMgJT4lIAogICAgbXV0YXRlKGludGVydmFsNjAgPSBtYXAoZGF0YSwgcHVsbCwgaW50ZXJ2YWw2MCksCiAgICAgICAgICAgc3RhcnRfc3RhdGlvbl9pZCA9IG1hcChkYXRhLCBwdWxsLCBzdGFydF9zdGF0aW9uX2lkKSwgCiAgICAgICAgICAgc3RhcnRfbGF0ID0gbWFwKGRhdGEsIHB1bGwsIHN0YXJ0X2xhdCksIAogICAgICAgICAgIHN0YXJ0X2xuZyA9IG1hcChkYXRhLCBwdWxsLCBzdGFydF9sbmcpLAogICAgICAgICAgIGRvdHcgPSBtYXAoZGF0YSwgcHVsbCwgZG90dykgKSAlPiUKICAgIHNlbGVjdChpbnRlcnZhbDYwLCBzdGFydF9zdGF0aW9uX2lkLCBzdGFydF9sbmcsIAogICAgICAgICAgIHN0YXJ0X2xhdCwgT2JzZXJ2ZWQsIFByZWRpY3Rpb24sIFJlZ3Jlc3Npb24sCiAgICAgICAgICAgZG90dykgJT4lCiAgICB1bm5lc3QoKSAlPiUKICBmaWx0ZXIoUmVncmVzc2lvbiA9PSAiRFRpbWVfU3BhY2VfRkVfdGltZUxhZ3MiKSU+JQogIG11dGF0ZSh3ZWVrZW5kID0gaWZlbHNlKGRvdHcgJWluJSBjKCJTdW4iLCAiU2F0IiksICJXZWVrZW5kIiwgIldlZWtkYXkiKSwKICAgICAgICAgdGltZV9vZl9kYXkgPSBjYXNlX3doZW4oaG91cihpbnRlcnZhbDYwKSA8IDcgfCBob3VyKGludGVydmFsNjApID4gMTggfiAiT3Zlcm5pZ2h0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG91cihpbnRlcnZhbDYwKSA+PSA3ICYgaG91cihpbnRlcnZhbDYwKSA8IDEwIH4gIkFNIFJ1c2giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob3VyKGludGVydmFsNjApID49IDEwICYgaG91cihpbnRlcnZhbDYwKSA8IDE1IH4gIk1pZC1EYXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob3VyKGludGVydmFsNjApID49IDE1ICYgaG91cihpbnRlcnZhbDYwKSA8PSAxOCB+ICJQTSBSdXNoIikpICU+JQogIGdyb3VwX2J5KHN0YXJ0X3N0YXRpb25faWQsIHdlZWtlbmQsIHRpbWVfb2ZfZGF5LCBzdGFydF9sbmcsIHN0YXJ0X2xhdCkgJT4lCiAgc3VtbWFyaXplKE1BRSA9IG1lYW4oYWJzKE9ic2VydmVkLVByZWRpY3Rpb24pLCBuYS5ybSA9IFRSVUUpKSU+JQogIGdncGxvdCguKSsKICBnZW9tX3NmKGRhdGEgPSBOSl9DZW5zdXMsIGNvbG9yID0gImdyZXkiLCBmaWxsID0gInRyYW5zcGFyZW50IikrCiAgIGdlb21fcG9pbnQoYWVzKHggPSBzdGFydF9sbmcsIHkgPSBzdGFydF9sYXQsIGNvbG9yID0gTUFFLCBzaXplID0gTUFFKSwgCiAgICAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IiwgYWxwaGEgPSAwLjYpICsKICBzY2FsZV9jb2xvdXJfdmlyaWRpcygKICAgIG5hbWUgPSAiTWVhbiBBYnNvbHV0ZSBFcnJvciIsICMgQ29tYmluZWQgdGl0bGUgZm9yIGNvbG9yIGFuZCBzaXplCiAgICBkaXJlY3Rpb24gPSAtMSwKICAgIG9wdGlvbiA9ICJEIiwKICAgIGRpc2NyZXRlID0gRkFMU0UKICApICsKICBzY2FsZV9zaXplX2NvbnRpbnVvdXMoCiAgICBuYW1lID0gIk1lYW4gQWJzb2x1dGUgRXJyb3IiLCAjIFNhbWUgdGl0bGUgYXMgY29sb3IgdG8gY29tYmluZSBsZWdlbmQKICAgIHJhbmdlID0gYygxLCA1KSAjIEFkanVzdCBzaXplIHJhbmdlIGFzIG5lZWRlZAogICkgKwogIGd1aWRlcygKICAgIGNvbG9yID0gZ3VpZGVfbGVnZW5kKCkgIyBVc2UgYSBzaW5nbGUgbGVnZW5kIGd1aWRlCiAgKSArCiAgeWxpbShtaW4oZGF0X2NlbnN1cyRzdGFydF9sYXQpLCBtYXgoZGF0X2NlbnN1cyRzdGFydF9sYXQpKSsKICB4bGltKG1pbihkYXRfY2Vuc3VzJHN0YXJ0X2xuZyksIG1heChkYXRfY2Vuc3VzJHN0YXJ0X2xuZykpKwogIGZhY2V0X2dyaWQod2Vla2VuZH50aW1lX29mX2RheSkrCiAgbGFicyh0aXRsZT0iTWVhbiBBYnNvbHV0ZSBFcnJvcnMsIFRlc3QgU2V0IikrCiAgbWFwVGhlbWUKYGBgCgpUaGUgbWFwcyBiZWxvdyBkaXNwbGF5IHRoZSBkaXN0cmlidXRpb24gb2YgTUFFIHZhbHVlcyBpbiBKZXJzZXkgQ2l0eSBkdXJpbmcgZGlmZmVyZW50IHRpbWUgcGVyaW9kcyBvbiB3ZWVrZGF5cyBhbmQgd2Vla2VuZHMuIE92ZXJhbGwsIGFyZWFzIG5lYXIgdGhlIEh1ZHNvbiBSaXZlciBleGhpYml0IHJlbGF0aXZlbHkgaGlnaGVyIE1BRSB2YWx1ZXMuIEFkZGl0aW9uYWxseSwgdGhlIG1vZGVsIHBlcmZvcm1zIGJldHRlciBkdXJpbmcgdGhlIG92ZXJuaWdodCBwZXJpb2QsIGFzIGluZGljYXRlZCBieSBsb3dlciBNQUUgdmFsdWVzLgoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CndlZWtfcHJlZGljdGlvbnMgJT4lIAogICAgbXV0YXRlKGludGVydmFsNjAgPSBtYXAoZGF0YSwgcHVsbCwgaW50ZXJ2YWw2MCksCiAgICAgICAgICAgc3RhcnRfc3RhdGlvbl9pZCA9IG1hcChkYXRhLCBwdWxsLCBzdGFydF9zdGF0aW9uX2lkKSwgCiAgICAgICAgICAgc3RhcnRfbGF0ID0gbWFwKGRhdGEsIHB1bGwsIHN0YXJ0X2xhdCksIAogICAgICAgICAgIHN0YXJ0X2xuZyA9IG1hcChkYXRhLCBwdWxsLCBzdGFydF9sbmcpLAogICAgICAgICAgIGRvdHcgPSBtYXAoZGF0YSwgcHVsbCwgZG90dykgKSAlPiUKICAgIHNlbGVjdChpbnRlcnZhbDYwLCBzdGFydF9zdGF0aW9uX2lkLCBzdGFydF9sbmcsIAogICAgICAgICAgIHN0YXJ0X2xhdCwgT2JzZXJ2ZWQsIFByZWRpY3Rpb24sIFJlZ3Jlc3Npb24sCiAgICAgICAgICAgZG90dykgJT4lCiAgICB1bm5lc3QoKSAlPiUKICBmaWx0ZXIoUmVncmVzc2lvbiA9PSAiRFRpbWVfU3BhY2VfRkVfdGltZUxhZ3MiKSU+JQogIG11dGF0ZSh3ZWVrZW5kID0gaWZlbHNlKGRvdHcgJWluJSBjKCJTdW4iLCAiU2F0IiksICJXZWVrZW5kIiwgIldlZWtkYXkiKSwKICAgICAgICAgdGltZV9vZl9kYXkgPSBjYXNlX3doZW4oaG91cihpbnRlcnZhbDYwKSA8IDcgfCBob3VyKGludGVydmFsNjApID4gMTggfiAiT3Zlcm5pZ2h0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG91cihpbnRlcnZhbDYwKSA+PSA3ICYgaG91cihpbnRlcnZhbDYwKSA8IDEwIH4gIkFNIFJ1c2giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob3VyKGludGVydmFsNjApID49IDEwICYgaG91cihpbnRlcnZhbDYwKSA8IDE1IH4gIk1pZC1EYXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob3VyKGludGVydmFsNjApID49IDE1ICYgaG91cihpbnRlcnZhbDYwKSA8PSAxOCB+ICJQTSBSdXNoIikpICU+JQogIGdyb3VwX2J5KHN0YXJ0X3N0YXRpb25faWQsIHdlZWtlbmQsIHRpbWVfb2ZfZGF5LCBzdGFydF9sbmcsIHN0YXJ0X2xhdCkgJT4lCiAgc3VtbWFyaXplKE1BRSA9IG1lYW4oYWJzKE9ic2VydmVkLVByZWRpY3Rpb24pLCBuYS5ybSA9IFRSVUUpKSU+JQogIGdncGxvdCguKSsKICBnZW9tX3NmKGRhdGEgPSBOSl9DZW5zdXMsIGNvbG9yID0gImdyZXkiLCBmaWxsID0gInRyYW5zcGFyZW50IikrCiAgIGdlb21fcG9pbnQoYWVzKHggPSBzdGFydF9sbmcsIHkgPSBzdGFydF9sYXQsIGNvbG9yID0gTUFFKSwgCiAgICAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IiwgYWxwaGEgPSAwLjUsIHNpemUgPSAxLjUpICsKICBzY2FsZV9jb2xvdXJfdmlyaWRpcyhkaXJlY3Rpb24gPSAtMSwKICBkaXNjcmV0ZSA9IEZBTFNFLCBvcHRpb24gPSAiRCIpICsKICB5bGltKG1pbihkYXRfY2Vuc3VzJHN0YXJ0X2xhdCksIG1heChkYXRfY2Vuc3VzJHN0YXJ0X2xhdCkpKwogIHhsaW0obWluKGRhdF9jZW5zdXMkc3RhcnRfbG5nKSwgbWF4KGRhdF9jZW5zdXMkc3RhcnRfbG5nKSkrCiAgZmFjZXRfZ3JpZCh3ZWVrZW5kfnRpbWVfb2ZfZGF5KSsKICBsYWJzKHRpdGxlPSJNZWFuIEFic29sdXRlIEVycm9ycywgVGVzdCBTZXQiKSsKICBtYXBUaGVtZQpgYGAKClRoZSBmb2xsb3dpbmcgc2NhdHRlcnBsb3RzIGV4cGxvcmUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGVycm9ycyBhbmQgc29jaW8tZWNvbm9taWMgZmVhdHVyZXMuIFRoZSBhbmFseXNpcyByZXZlYWxzIHRoYXQgYXJlYXMgd2l0aCBsb3dlciBpbmNvbWUsIGEgc21hbGxlciBwcm9wb3J0aW9uIG9mIHJlc2lkZW50cyB1c2luZyBwdWJsaWMgdHJhbnNwb3J0YXRpb24sIGFuZCBhIGxvd2VyIHBlcmNlbnRhZ2Ugb2Ygd2hpdGUgcmVzaWRlbnRzIHRlbmQgdG8gaGF2ZSBsb3dlciBNQUUgdmFsdWVzLCBpbmRpY2F0aW5nIHRoYXQgdGhlc2UgYXJlYXMgYXJlIG1vcmUgYWNjdXJhdGVseSBwcmVkaWN0ZWQgYnkgdGhlIG1vZGVsLgoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CndlZWtfcHJlZGljdGlvbnMgJT4lIAogICAgbXV0YXRlKGludGVydmFsNjAgPSBtYXAoZGF0YSwgcHVsbCwgaW50ZXJ2YWw2MCksCiAgICAgICAgICAgc3RhcnRfc3RhdGlvbl9pZCA9IG1hcChkYXRhLCBwdWxsLCBzdGFydF9zdGF0aW9uX2lkKSwgCiAgICAgICAgICAgc3RhcnRfbGF0ID0gbWFwKGRhdGEsIHB1bGwsIHN0YXJ0X2xhdCksIAogICAgICAgICAgIHN0YXJ0X2xuZyA9IG1hcChkYXRhLCBwdWxsLCBzdGFydF9sbmcpLAogICAgICAgICAgIGRvdHcgPSBtYXAoZGF0YSwgcHVsbCwgZG90dyksCiAgICAgICAgICAgUGVyY2VudF9UYWtpbmdfUHVibGljX1RyYW5zID0gbWFwKGRhdGEsIHB1bGwsIFBlcmNlbnRfVGFraW5nX1B1YmxpY19UcmFucyksCiAgICAgICAgICAgTWVkX0luYyA9IG1hcChkYXRhLCBwdWxsLCBNZWRfSW5jKSwKICAgICAgICAgICBQZXJjZW50X1doaXRlID0gbWFwKGRhdGEsIHB1bGwsIFBlcmNlbnRfV2hpdGUpKSAlPiUKICAgIHNlbGVjdChpbnRlcnZhbDYwLCBzdGFydF9zdGF0aW9uX2lkLCBzdGFydF9sYXQsIAogICAgICAgICAgIHN0YXJ0X2xuZywgT2JzZXJ2ZWQsIFByZWRpY3Rpb24sIFJlZ3Jlc3Npb24sCiAgICAgICAgICAgZG90dywgUGVyY2VudF9UYWtpbmdfUHVibGljX1RyYW5zLCBNZWRfSW5jLCBQZXJjZW50X1doaXRlKSAlPiUKICAgIHVubmVzdCgpICU+JQogIGZpbHRlcihSZWdyZXNzaW9uID09ICJEVGltZV9TcGFjZV9GRV90aW1lTGFncyIpJT4lCiAgbXV0YXRlKHdlZWtlbmQgPSBpZmVsc2UoZG90dyAlaW4lIGMoIlN1biIsICJTYXQiKSwgIldlZWtlbmQiLCAiV2Vla2RheSIpLAogICAgICAgICB0aW1lX29mX2RheSA9IGNhc2Vfd2hlbihob3VyKGludGVydmFsNjApIDwgNyB8IGhvdXIoaW50ZXJ2YWw2MCkgPiAxOCB+ICJPdmVybmlnaHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob3VyKGludGVydmFsNjApID49IDcgJiBob3VyKGludGVydmFsNjApIDwgMTAgfiAiQU0gUnVzaCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gMTAgJiBob3VyKGludGVydmFsNjApIDwgMTUgfiAiTWlkLURheSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gMTUgJiBob3VyKGludGVydmFsNjApIDw9IDE4IH4gIlBNIFJ1c2giKSkgJT4lCiAgZmlsdGVyKHRpbWVfb2ZfZGF5ID09ICJBTSBSdXNoIikgJT4lCiAgZ3JvdXBfYnkoc3RhcnRfc3RhdGlvbl9pZCwgUGVyY2VudF9UYWtpbmdfUHVibGljX1RyYW5zLCBNZWRfSW5jLCBQZXJjZW50X1doaXRlKSAlPiUKICBzdW1tYXJpemUoTUFFID0gbWVhbihhYnMoT2JzZXJ2ZWQtUHJlZGljdGlvbiksIG5hLnJtID0gVFJVRSkpJT4lCiAgZ2F0aGVyKC1zdGFydF9zdGF0aW9uX2lkLCAtTUFFLCBrZXkgPSAidmFyaWFibGUiLCB2YWx1ZSA9ICJ2YWx1ZSIpJT4lCiAgZ2dwbG90KC4pKwogICNnZW9tX3NmKGRhdGEgPSBjaGljYWdvQ2Vuc3VzLCBjb2xvciA9ICJncmV5IiwgZmlsbCA9ICJ0cmFuc3BhcmVudCIpKwogIGdlb21fcG9pbnQoYWVzKHggPSB2YWx1ZSwgeSA9IE1BRSksIGFscGhhID0gMC40KSsKICBnZW9tX3Ntb290aChhZXMoeCA9IHZhbHVlLCB5ID0gTUFFKSwgbWV0aG9kID0gImxtIiwgc2U9IEZBTFNFKSsKICBmYWNldF93cmFwKH52YXJpYWJsZSwgc2NhbGVzID0gImZyZWUiKSsKICBsYWJzKHRpdGxlPSJFcnJvcnMgYXMgYSBmdW5jdGlvbiBvZiBzb2Npby1lY29ub21pYyB2YXJpYWJsZXMiLAogICAgICAgeT0iTWVhbiBBYnNvbHV0ZSBFcnJvciAoVHJpcHMpIikrCiAgcGxvdFRoZW1lCmBgYAoKIyBDb25jbHVzaW9uCgpPdmVyYWxsLCBiaWtlIHN0YXRpb25zIG5lYXIgdGhlIEh1ZHNvbiBSaXZlciwgcGFydGljdWxhcmx5IHRob3NlIGNsb3NlIHRvIE1hbmhhdHRhbiwgZXhoaWJpdCBoaWdoZXIgYmlrZSBzaGFyZSBjb3VudHMsIGxpa2VseSByZWZsZWN0aW5nIGEgaGlnaCB2b2x1bWUgb2YgY29tbXV0ZXJzIHRyYXZlbGluZyBmb3Igd29yaywgc3R1ZHksIG9yIG90aGVyIGRhaWx5IGFjdGl2aXRpZXMuIEFkZGl0aW9uYWxseSwgdGhlc2Ugc3RhdGlvbnMgdGVuZCB0byBoYXZlIHJlbGF0aXZlbHkgbGFyZ2VyIE1lYW4gQWJzb2x1dGUgRXJyb3IgKE1BRSkgdmFsdWVzLCBzaG93aW5nIGEgdGVuZGVuY3kgZm9yIHVuZGVyLXByZWRpY3Rpb24gY29tcGFyZWQgdG8gb3RoZXIgc3RhdGlvbnMuIFRoaXMgc3VnZ2VzdHMgYSBoaWdoIGRlbWFuZCBmb3IgYmlrZXMgaW4gYXJlYXMgbmVhciB0aGUgSHVkc29uIFJpdmVyLiBUbyBhZGRyZXNzIGJpa2UgcmUtYmFsYW5jaW5nIHBsYW4sIGl0IGlzIGVzc2VudGlhbCB0byBlbnN1cmUgdGhhdCBzdGF0aW9ucyBhbnRpY2lwYXRlZCB0byBleHBlcmllbmNlIGhpZ2ggZGVtYW5kIGFyZSBhZGVxdWF0ZWx5IHN1cHBsaWVkIHdpdGggYmlrZXMuIEJhc2VkIG9uIHRoZSBtb2RlbCBhbmFseXNpcywgYWxsb2NhdGluZyBtb3JlIGJpa2VzIHRvIHN0YXRpb25zIG5lYXIgdGhlIEh1ZHNvbiBSaXZlciBpcyBhIG5lY2Vzc2FyeSBzdGVwIHRvIG1lZXQgdGhpcyBkZW1hbmQgZWZmZWN0aXZlbHkuCg==